package com.coderush.admin.core.utils;


import com.coderush.admin.core.annotation.ConvertDateField;
import com.coderush.admin.core.annotation.ConvertEnumField;
import com.coderush.admin.core.annotation.ConvertStrIdField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;

/**
 * ClassName: BeanUtil
 * Package: com.javasetest.utils
 * Description:
 *
 * @Author wxz
 * @Create 2024/4/12 16:08
 * @Version 1.0
 */
public class BeanConvertUtil {

    private static final Logger logger = LoggerFactory.getLogger(BeanConvertUtil.class);

    /**
     * 字段转换
     *
     * @param sourceObj 源数据
     * @param targetObj 目标数据
     */
    public static void fieldConvert(Object sourceObj, Object targetObj) {

        // 获取目标数据的所有字段
        Field[] targetFields = targetObj.getClass().getDeclaredFields();

        // 遍历所有字段是否标注了注解
        Arrays.stream(targetFields).forEach(field -> {
            // 由于这是私有字段，我们需要设置为可访问
            field.setAccessible(true);

            // 获取属性上的注解 ConvertStatusToStr
            ConvertEnumField convertEnumFieldAnno = field.getDeclaredAnnotation(ConvertEnumField.class);
            if (convertEnumFieldAnno != null) {
                try {
                    // 处理标注了 ConvertEnumField 注解的字段
                    convertEnumFieldHandler(sourceObj, targetObj, field, convertEnumFieldAnno);
                } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
            ConvertDateField convertDateFieldAnno = field.getDeclaredAnnotation(ConvertDateField.class);
            if (convertDateFieldAnno != null) {
                try {
                    // 处理标注了 convertDateField 注解的字段
                    convertDateFieldHandler(sourceObj, targetObj, field, convertDateFieldAnno);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
            ConvertStrIdField convertStrIdFieldAnno = field.getDeclaredAnnotation(ConvertStrIdField.class);
            if (convertStrIdFieldAnno != null) {
                try {
                    // 处理标注了 ConvertStrIdField 注解的字段
                    convertStrIdFieldHandler(sourceObj, targetObj, field, convertStrIdFieldAnno);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }


        });
    }

    /**
     * 处理标注了 ConvertStrIdField 注解的字段
     *
     * @param sourceObj            源数据
     * @param targetObj            目标数据
     * @param field                要处理的字段
     * @param convertStrIdFieldAnno 自定义的注解
     */
    private static void convertStrIdFieldHandler(Object sourceObj, Object targetObj, Field field, ConvertStrIdField convertStrIdFieldAnno) throws NoSuchFieldException, IllegalAccessException {

        // 获取属性上注解的信息
        String sourceFieldName = convertStrIdFieldAnno.sourceFieldName();

        // 从源数据中获取需要转化的属性的值
        Field sourceField = sourceObj.getClass().getDeclaredField(sourceFieldName);
        // 由于这是私有字段，我们需要设置为可访问
        sourceField.setAccessible(true);
        // 字段值
        Object value = sourceField.get(sourceObj);

        field.set(targetObj, String.valueOf(value));
    }

    /**
     * 处理标注了 convertDateField 注解的字段
     *
     * @param sourceObj            源数据
     * @param targetObj            目标数据
     * @param field                要处理的字段
     * @param convertDateFieldAnno 自定义的注解
     */
    private static void convertDateFieldHandler(Object sourceObj, Object targetObj, Field field, ConvertDateField convertDateFieldAnno) throws NoSuchFieldException, IllegalAccessException {

        // 获取属性上注解的信息
        String sourceFieldName = convertDateFieldAnno.sourceFieldName();
        String pattern = convertDateFieldAnno.pattern();

        // 从源数据中获取需要转化的属性的值
        Field sourceField = sourceObj.getClass().getDeclaredField(sourceFieldName);
        // 由于这是私有字段，我们需要设置为可访问
        sourceField.setAccessible(true);
        // 字段值
        Object value = sourceField.get(sourceObj);

        // 日期类型格式化
        LocalDateTime dateValue = (LocalDateTime) value;
        String format = dateValue.format(DateTimeFormatter.ofPattern(pattern));

        field.set(targetObj, format);

    }

    /**
     * 处理标注了 ConvertEnumField 注解的字段
     *
     * @param sourceObj            源数据
     * @param targetObj            目标数据
     * @param field                要处理的字段
     * @param convertEnumFieldAnno 自定义的注解
     */
    private static void convertEnumFieldHandler(Object sourceObj, Object targetObj, Field field, ConvertEnumField convertEnumFieldAnno) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {

        // 获取属性上注解定义的枚举类(全限定类名)
        String enumClasName = convertEnumFieldAnno.enumClass().getTypeName();
        // 获取属性上注解定义的实体类的字段名
        String sourceFieldName = convertEnumFieldAnno.sourceFieldName();

        // 从源数据中获取需要转化的属性的值
        Field sourceField = sourceObj.getClass().getDeclaredField(sourceFieldName);
        // 由于这是私有字段，我们需要设置为可访问
        sourceField.setAccessible(true);
        // 字段值
        Object value = sourceField.get(sourceObj);

        // 从枚举中获取枚举信息
        String message = getEnumMessage((int) value, enumClasName);

        field.set(targetObj, message);

    }

    /**
     * 从枚举中获取枚举信息
     *
     * @param status 枚举值
     * @param classPath 枚举信息
     * @return 枚举信息
     */
    private static String getEnumMessage(Integer status, String classPath) throws ClassNotFoundException {

        Object[] enumConstants = Class.forName(classPath).getEnumConstants();
        if (enumConstants == null || enumConstants.length <= 0) {
            return "";
        }

        String str = "";

        for (Object enumConstant : enumConstants) {

            Field codeField = null;
            Field messageField = null;
            try {
                codeField = enumConstant.getClass().getDeclaredField("code");
                messageField = enumConstant.getClass().getDeclaredField("message");
                codeField.setAccessible(true);
                messageField.setAccessible(true);

                int code = (int) codeField.get(enumConstant);
                String message = (String) messageField.get(enumConstant);

                if (status == code) {
                    str = message;
                    break;
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }

        return str;
    }

}
